home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / dev / src / chunkyiclass.lha / chunkyiclass.c next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  16.5 KB  |  644 lines

  1. /*
  2.  * chunkyiclass.c
  3.  * ==============
  4.  * Implementation of chunky image class.
  5.  *
  6.  * Copyright © 1995 Lorens Younes (d93-hyo@nada.kth.se)
  7.  */
  8.  
  9. #include <clib/alib_protos.h>
  10. #include <exec/memory.h>
  11. #include <proto/exec.h>
  12. #include <graphics/gfxbase.h>
  13. #include <graphics/scale.h>
  14. #include <proto/graphics.h>
  15. #include <proto/intuition.h>
  16. #include <proto/utility.h>
  17.  
  18. #include "chunkyiclass.h"
  19.  
  20.  
  21. struct rp_info {
  22.    UWORD             width, height;
  23.    struct RastPort  *rp;
  24. };
  25.  
  26. /* instance data for chunkyiclass */
  27. struct chunkyidata {
  28.    struct Screen   *screen;
  29.    UWORD            selected_bgpen;
  30.    ULONG            num_pens;
  31.    LONG            *shared_pens;
  32.    UWORD           *def_pens;
  33.    UBYTE           *selected_data;
  34.    struct rp_info   normal_rpi, selected_rpi;
  35. };
  36.  
  37.  
  38. /* macros to extract components of CHUNKYIA_Palette (n >= 1) */
  39. #define PALETTE_ENTRIES(p)    (*(p))
  40. #define PALETTE_RED(p, n)     (*((p) + (3 * (n)) - 2))
  41. #define PALETTE_GREEN(p, n)   (*((p) + (3 * (n)) - 1))
  42. #define PALETTE_BLUE(p, n)    (*((p) + (3 * (n))))
  43.  
  44.  
  45. /* macros to extract components of IA_Data and CHUNKYIA_SelectedData */
  46. #define IMAGE_WIDTH(i)    (((UWORD *)(i))[0])
  47. #define IMAGE_HEIGHT(i)   (((UWORD *)(i))[1])
  48. #define IMAGE_DATA(i)     (&(i)[4])
  49.  
  50.  
  51. /* frees rastport */
  52. static void
  53. free_rastport (
  54.    struct RastPort  *rp,
  55.    UWORD             width,
  56.    UWORD             height)
  57. {
  58.    if (rp && rp->BitMap)
  59.    {
  60.       if (GfxBase->LibNode.lib_Version >= 39L)
  61.          FreeBitMap (rp->BitMap);
  62.       else
  63.       {
  64.          register UBYTE   i;
  65.          
  66.          
  67.          for (i = 0; i < rp->BitMap->Depth; ++i)
  68.          {
  69.             if (rp->BitMap->Planes[i] != NULL)
  70.             {
  71.                FreeRaster (rp->BitMap->Planes[i], width, height);
  72.             }
  73.          }
  74.          FreeVec (rp->BitMap);
  75.       }
  76.    }
  77.    FreeVec (rp);
  78. }
  79.  
  80.  
  81. /* creates a rastport */
  82. static struct RastPort *
  83. init_rastport (
  84.    struct RastPort  *parent_rp,
  85.    UWORD             width,
  86.    UWORD             height)
  87. {
  88.    struct RastPort  *rp;
  89.    
  90.    
  91.    if (rp = AllocVec (sizeof (*rp), MEMF_PUBLIC))
  92.    {
  93.       *rp = *parent_rp;
  94.       rp->Layer = NULL;
  95.       
  96.       if (GfxBase->LibNode.lib_Version >= 39L)
  97.       {
  98.          if (!(rp->BitMap = AllocBitMap (width, height,
  99.                                          parent_rp->BitMap->Depth, 0,
  100.                                          parent_rp->BitMap)))
  101.          {
  102.             free_rastport (rp, width, height);
  103.             rp = NULL;
  104.          }
  105.       }
  106.       else
  107.       {
  108.          register UBYTE   i;
  109.          
  110.          
  111.          if (rp->BitMap = AllocVec (sizeof (*rp->BitMap), MEMF_PUBLIC))
  112.          {
  113.             InitBitMap (rp->BitMap, parent_rp->BitMap->Depth, width, height);
  114.             for (i = 0; i < rp->BitMap->Depth; ++i)
  115.                rp->BitMap->Planes[i] = NULL;
  116.             for (i = 0; i < rp->BitMap->Depth; ++i)
  117.             {
  118.                if (!(rp->BitMap->Planes[i] = (PLANEPTR)
  119.                                              AllocRaster (width, height)))
  120.                {
  121.                   free_rastport (rp, width, height);
  122.                   rp = NULL;
  123.                }
  124.             }
  125.          }
  126.       }
  127.    }
  128.    
  129.    return rp;
  130. }
  131.  
  132.  
  133. static void
  134. free_shared_pens (
  135.    struct chunkyidata  *data)
  136. {
  137.    register ULONG   n;
  138.    
  139.    
  140.    if (data->shared_pens)
  141.    {
  142.       for (n = 0; n < data->num_pens; ++n)
  143.       {
  144.          if (data->shared_pens[n] != -1)
  145.          {
  146.             ReleasePen (data->screen->ViewPort.ColorMap,
  147.                         data->shared_pens[n]);
  148.          }
  149.       }
  150.       FreeVec (data->shared_pens);
  151.       data->shared_pens = NULL;
  152.    }
  153. }
  154.  
  155.  
  156. static void
  157. init_shared_pens (
  158.    struct chunkyidata  *data,
  159.    ULONG               *palette)
  160. {
  161.    register ULONG   n;
  162.    
  163.    
  164.    free_shared_pens (data);
  165.    
  166.    if (palette)
  167.    {
  168.       data->num_pens = PALETTE_ENTRIES (palette);
  169.       data->shared_pens = AllocVec (data->num_pens *
  170.                                     sizeof (*data->shared_pens),
  171.                                     MEMF_PUBLIC);
  172.    }
  173.    
  174.    if (GfxBase->LibNode.lib_Version >= 39L &&
  175.        data->shared_pens && data->screen)
  176.    {
  177.       for (n = 1; n <= data->num_pens; ++n)
  178.       {
  179.          data->shared_pens[n - 1] = ObtainBestPen (
  180.                                              data->screen->ViewPort.ColorMap,
  181.                                              PALETTE_RED (palette, n),
  182.                                              PALETTE_GREEN (palette, n),
  183.                                              PALETTE_BLUE (palette, n),
  184.                                              OBP_Precision, PRECISION_IMAGE,
  185.                                              TAG_DONE);
  186.       }
  187.    }
  188.    else /* no pens could be obtained - IA_Pens will be used */
  189.    {
  190.       FreeVec (data->shared_pens);
  191.       data->shared_pens = NULL;
  192.    }
  193. }
  194.  
  195.  
  196. static void
  197. free_image (
  198.    struct rp_info  *rpi)
  199. {
  200.    free_rastport (rpi->rp, rpi->width, rpi->height);
  201.    rpi->rp = NULL;
  202. }
  203.  
  204.  
  205. static void
  206. init_image (
  207.    struct RastPort  *parent_rp,
  208.    struct rp_info   *rpi,
  209.    UBYTE            *imagedata,
  210.    LONG             *shared_pens,
  211.    UWORD            *def_pens,
  212.    UWORD             bgpen)
  213. {
  214.    register UWORD   x, y;
  215.    
  216.    
  217.    free_image (rpi);
  218.    
  219.    if (imagedata && parent_rp)
  220.    {
  221.       if (rpi->rp = init_rastport (parent_rp,
  222.                                    rpi->width, rpi->height))
  223.       {
  224.          for (y = 0; y < rpi->height; ++y)
  225.          {
  226.             for (x = 0; x < rpi->width; ++x)
  227.             {
  228.                if (imagedata[x + y * rpi->width] == 0) /* use BACKGROUNDPEN */
  229.                   SetAPen (rpi->rp, bgpen);
  230.                else
  231.                {
  232.                   if (shared_pens &&
  233.                       shared_pens[imagedata[x + y * rpi->width] - 1] != -1)
  234.                   {
  235.                      SetAPen (rpi->rp,
  236.                               shared_pens[imagedata[x + y * rpi->width] - 1]);
  237.                   }
  238.                   else if (def_pens)
  239.                   {
  240.                      SetAPen (rpi->rp,
  241.                               def_pens[imagedata[x + y * rpi->width] - 1]);
  242.                   }
  243.                   else
  244.                   {
  245.                      SetAPen (rpi->rp,
  246.                               imagedata[x + y * rpi->width]);
  247.                   }
  248.                }
  249.                
  250.                WritePixel (rpi->rp, x, y);
  251.             }
  252.          }
  253.       }
  254.    }
  255. }
  256.  
  257. /* OM_NEW method for chunkyiclass */
  258. static void
  259. chunkyim_new (
  260.    Class         *cl,
  261.    Object        *obj,
  262.    struct opSet  *msg)
  263. {
  264.    struct chunkyidata  *data = INST_DATA (cl, obj);
  265.    UBYTE               *normal_data = NULL;
  266.    struct DrawInfo     *dri = NULL;
  267.    ULONG                bgpen;
  268.    
  269.    
  270.    /* If IA_Width or IA_Height are not explicitly given on initialization, */
  271.    /* set them to their corresponding values in IA_Data.                   */
  272.    GetAttr (IA_Data, obj, (ULONG *)&normal_data);
  273.    if (normal_data != NULL)
  274.    {
  275.       if (!FindTagItem (IA_Width, msg->ops_AttrList))
  276.          ((struct Image *)obj)->Width = IMAGE_WIDTH (normal_data);
  277.       if (!FindTagItem (IA_Height, msg->ops_AttrList))
  278.          ((struct Image *)obj)->Height = IMAGE_HEIGHT (normal_data);
  279.    }
  280.    
  281.    
  282.    /* Initialize image palette. */
  283.    data->shared_pens = NULL;
  284.    data->screen = (struct Screen *)
  285.                   GetTagData (CHUNKYIA_Screen, NULL, msg->ops_AttrList);
  286.    init_shared_pens (data,
  287.                      (ULONG *)
  288.                      GetTagData (CHUNKYIA_Palette, NULL, msg->ops_AttrList));
  289.    
  290.    if (data->screen)
  291.       dri = GetScreenDrawInfo (data->screen);
  292.    if (!FindTagItem (IA_BGPen, msg->ops_AttrList))
  293.    {
  294.       ((struct Image *)obj)->PlaneOnOff = (dri) ?
  295.                                           dri->dri_Pens[BACKGROUNDPEN] : 0;
  296.    }
  297.    data->selected_bgpen = GetTagData (CHUNKYIA_SelectedBGPen,
  298.                                       ((dri) ? dri->dri_Pens[FILLPEN] : 0),
  299.                                       msg->ops_AttrList);
  300.    if (dri)
  301.       FreeScreenDrawInfo (data->screen, dri);
  302.    
  303.    
  304.    /* Create images in their own rastports. */
  305.    data->selected_data = (UBYTE *)GetTagData (CHUNKYIA_SelectedData, NULL,
  306.                                               msg->ops_AttrList);
  307.    GetAttr (IA_BGPen, obj, (ULONG *)&bgpen);
  308.    data->def_pens = (UWORD *)GetTagData (IA_Pens, NULL, msg->ops_AttrList);
  309.    
  310.    if (data->screen)
  311.    {
  312.       if (normal_data)
  313.       {
  314.          data->normal_rpi.width = IMAGE_WIDTH (normal_data);
  315.          data->normal_rpi.height = IMAGE_HEIGHT (normal_data);
  316.          init_image (&data->screen->RastPort, &data->normal_rpi,
  317.                      IMAGE_DATA (normal_data),
  318.                      data->shared_pens, data->def_pens, bgpen);
  319.       }
  320.       if (data->selected_data)
  321.       {
  322.          data->selected_rpi.width = IMAGE_WIDTH (data->selected_data);
  323.          data->selected_rpi.height = IMAGE_HEIGHT (data->selected_data);
  324.          init_image (&data->screen->RastPort, &data->selected_rpi,
  325.                      IMAGE_DATA (data->selected_data),
  326.                      data->shared_pens, data->def_pens, data->selected_bgpen);
  327.       }
  328.    }
  329. }
  330.  
  331.  
  332. /* OM_DISPOSE method for chunkyiclass */
  333. static void
  334. chunkyim_dispose (
  335.    Class   *cl,
  336.    Object  *obj)
  337. {
  338.    struct chunkyidata  *data = INST_DATA (cl, obj);
  339.    
  340.    
  341.    free_shared_pens (data);
  342.    free_image (&data->normal_rpi);
  343.    free_image (&data->selected_rpi);
  344. }
  345.  
  346.  
  347. /* OM_GET method for chunkyiclass */
  348. static BOOL
  349. chunkyim_get (
  350.    Class         *cl,
  351.    Object        *obj,
  352.    struct opGet  *msg)
  353. {
  354.    struct chunkyidata  *data = INST_DATA (cl, obj);
  355.    BOOL                 retval = TRUE;
  356.    
  357.    
  358.    switch (msg->opg_AttrID)
  359.    {
  360.    case IA_Pens:
  361.       *msg->opg_Storage = (ULONG)data->def_pens;
  362.       break;
  363.    case CHUNKYIA_SelectedBGPen:
  364.       *msg->opg_Storage = data->selected_bgpen;
  365.       break;
  366.    case CHUNKYIA_SelectedData:
  367.       *msg->opg_Storage = (ULONG)data->selected_data;
  368.       break;
  369.    case CHUNKYIA_Screen:
  370.       *msg->opg_Storage = (ULONG)data->screen;
  371.       break;
  372.    default:
  373.       retval = FALSE;
  374.       break;
  375.    }
  376.    
  377.    return retval;
  378. }
  379.  
  380.  
  381. /* OM_SET method for chunkyiclass */
  382. static void
  383. chunkyim_set (
  384.    Class         *cl,
  385.    Object        *obj,
  386.    struct opSet  *msg)
  387. {
  388.    struct chunkyidata  *data = INST_DATA (cl, obj);
  389.    struct TagItem      *ti, *tstate = msg->ops_AttrList;
  390.    BOOL                 nimg_update = FALSE, simg_update = FALSE;
  391.    UBYTE               *normal_data = NULL;
  392.    ULONG                bgpen;
  393.    
  394.    
  395.    while (ti = NextTagItem (&tstate))
  396.    {
  397.       switch (ti->ti_Tag)
  398.       {
  399.       case IA_Pens:
  400.          data->def_pens = (UWORD *)ti->ti_Data;
  401.          nimg_update = simg_update = TRUE;
  402.          break;
  403.       case IA_BGPen:
  404.       case IA_Data:
  405.          nimg_update = TRUE;
  406.          break;
  407.       case CHUNKYIA_SelectedBGPen:
  408.          data->selected_bgpen = ti->ti_Data;
  409.          simg_update = TRUE;
  410.          break;
  411.       case CHUNKYIA_SelectedData:
  412.          if (data->selected_data = (UBYTE *)ti->ti_Data)
  413.             simg_update = TRUE;
  414.          else
  415.             free_image (&data->selected_rpi);
  416.          break;
  417.       case CHUNKYIA_Palette:
  418.          init_shared_pens (data, (ULONG *)ti->ti_Data);
  419.          nimg_update = simg_update = TRUE;
  420.          break;
  421.       }
  422.    }
  423.    
  424.    GetAttr (IA_Data, obj, (ULONG *)&normal_data);
  425.    if (nimg_update && data->screen && normal_data)
  426.    {
  427.       GetAttr (IA_BGPen, obj, &bgpen);
  428.       data->normal_rpi.width = IMAGE_WIDTH (normal_data);
  429.       data->normal_rpi.height = IMAGE_HEIGHT (normal_data);
  430.       
  431.       init_image (&data->screen->RastPort, &data->normal_rpi,
  432.                   IMAGE_DATA (normal_data),
  433.                   data->shared_pens, data->def_pens, bgpen);
  434.    }
  435.    if (simg_update && data->screen && data->selected_data)
  436.    {
  437.       data->selected_rpi.width = IMAGE_WIDTH (data->selected_data);
  438.       data->selected_rpi.height = IMAGE_HEIGHT (data->selected_data);
  439.       
  440.       init_image (&data->screen->RastPort, &data->selected_rpi,
  441.                   IMAGE_DATA (data->selected_data),
  442.                   data->shared_pens, data->def_pens, data->selected_bgpen);
  443.    }
  444. }
  445.  
  446.  
  447. /* IM_DRAW method for chunkyiclass */
  448. static void
  449. chunkyim_draw (
  450.    Class           *cl,
  451.    Object          *obj,
  452.    struct impDraw  *msg)
  453. {
  454.    struct chunkyidata  *data = INST_DATA (cl, obj);
  455.    struct rp_info      *rpi;
  456.    LONG                 left, top;
  457.    ULONG                width, height;
  458.    
  459.    
  460.    switch (msg->imp_State)
  461.    {
  462.    case IDS_SELECTED:
  463.    case IDS_INACTIVESELECTED:
  464.       rpi = &data->selected_rpi;
  465.       break;
  466.    default:
  467.       rpi = &data->normal_rpi;
  468.       break;
  469.    }
  470.    if (!rpi->rp)
  471.       rpi = &data->normal_rpi;
  472.    
  473.    if (rpi->rp)
  474.    {
  475.       GetAttr (IA_Left, obj, (ULONG *)&left);
  476.       GetAttr (IA_Top, obj, (ULONG *)&top);
  477.       if (msg->MethodID == IM_DRAWFRAME)
  478.       {
  479.          width = msg->imp_Dimensions.Width;
  480.          height = msg->imp_Dimensions.Height;
  481.       }
  482.       else
  483.       {
  484.          GetAttr (IA_Width, obj, &width);
  485.          GetAttr (IA_Height, obj, &height);
  486.       }
  487.       left += msg->imp_Offset.X;
  488.       top += msg->imp_Offset.Y;
  489.       
  490.       if (width == rpi->width && height == rpi->height)
  491.       {
  492.          ClipBlit (rpi->rp, 0, 0, msg->imp_RPort, left, top,
  493.                    rpi->width, rpi->height, 0xC0);
  494.       }
  495.       else
  496.       {
  497.          struct BitScaleArgs   bsa;
  498.          struct RastPort      *temp_rp;
  499.          
  500.          
  501.          if (temp_rp = init_rastport (msg->imp_RPort, width, height))
  502.          {
  503.             bsa.bsa_SrcX = 0;
  504.             bsa.bsa_SrcY = 0;
  505.             bsa.bsa_SrcWidth = rpi->width;
  506.             bsa.bsa_SrcHeight = rpi->height;
  507.             bsa.bsa_XSrcFactor = rpi->width;
  508.             bsa.bsa_YSrcFactor = rpi->height;
  509.             bsa.bsa_DestX = 0;
  510.             bsa.bsa_DestY = 0;
  511.             bsa.bsa_DestWidth = width;
  512.             bsa.bsa_DestHeight = height;
  513.             bsa.bsa_XDestFactor = width;
  514.             bsa.bsa_YDestFactor = height;
  515.             bsa.bsa_SrcBitMap = rpi->rp->BitMap;
  516.             bsa.bsa_DestBitMap = temp_rp->BitMap;
  517.             bsa.bsa_Flags = 0;
  518.             
  519.             BitMapScale (&bsa);
  520.             ClipBlit (temp_rp, 0, 0, msg->imp_RPort, left, top,
  521.                       width, height, 0xC0);
  522.             
  523.             free_rastport (temp_rp, width, height);
  524.          }
  525.       }
  526.    }
  527. }
  528.  
  529.  
  530. /* IM_HITFRAME method for chunkyiclass */
  531. static BOOL
  532. chunkyim_hitframe (
  533.    Class              *cl,
  534.    Object             *obj,
  535.    struct impHitTest  *msg)
  536. {
  537.    LONG   left, top;
  538.    
  539.    
  540.    GetAttr (IA_Left, obj, (ULONG *)&left);
  541.    GetAttr (IA_Top, obj, (ULONG *)&top);
  542.    
  543.    return (BOOL)(msg->imp_Point.X >= left && msg->imp_Point.Y >= top &&
  544.                  msg->imp_Point.X < left + msg->imp_Dimensions.Width &&
  545.                  msg->imp_Point.Y < left + msg->imp_Dimensions.Height);
  546. }
  547.  
  548.  
  549. /* IM_ERASEFRAME method for chunkyiclass */
  550. static void
  551. chunkyim_eraseframe (
  552.    Class            *cl,
  553.    Object           *obj,
  554.    struct impErase  *msg)
  555. {
  556.    LONG   left, top;
  557.    
  558.    
  559.    GetAttr (IA_Left, obj, (ULONG *)&left);
  560.    GetAttr (IA_Top, obj, (ULONG *)&top);
  561.    left += msg->imp_Offset.X;
  562.    top += msg->imp_Offset.Y;
  563.    
  564.    EraseRect (msg->imp_RPort, left, top,
  565.               left + msg->imp_Dimensions.Width - 1,
  566.               top + msg->imp_Dimensions.Height - 1);
  567. }
  568.  
  569.  
  570. /* !!!dispatcher for chunkyiclass!!! */
  571. ULONG __saveds
  572. chunkyi_dispatcher (
  573.    Class   *cl,
  574.    Object  *obj,
  575.    Msg      msg)
  576. {
  577.    APTR   retval = NULL;
  578.    
  579.    
  580.    switch (msg->MethodID)
  581.    {
  582.    case OM_NEW:
  583.       if (retval = (APTR)DoSuperMethodA (cl, obj, msg))
  584.          chunkyim_new (cl, retval, (struct opSet *)msg);
  585.       break;
  586.    case OM_DISPOSE:
  587.       chunkyim_dispose (cl, obj);
  588.       retval = (APTR)DoSuperMethodA (cl, obj, msg);
  589.       break;
  590.    case OM_GET:
  591.       if (!(retval = (APTR)chunkyim_get (cl, obj, (struct opGet *)msg)))
  592.          retval = (APTR)DoSuperMethodA (cl, obj, msg);
  593.       break;
  594.    case OM_SET:
  595.       retval = (APTR)1;
  596.       DoSuperMethodA (cl, obj, msg);
  597.       chunkyim_set (cl, obj, (struct opSet *)msg);
  598.       break;
  599.    case IM_DRAW:
  600.    case IM_DRAWFRAME:
  601.       chunkyim_draw (cl, obj, (struct impDraw *)msg);
  602.       break;
  603.    case IM_HITFRAME:
  604.       retval = (APTR)chunkyim_hitframe (cl, obj, (struct impHitTest *)msg);
  605.       break;
  606.    case IM_ERASEFRAME:
  607.       chunkyim_eraseframe (cl, obj, (struct impErase *)msg);
  608.       break;
  609.    default: /* method not recognized by chunkyiclass */
  610.       retval = (APTR)DoSuperMethodA (cl, obj, msg);
  611.       break;
  612.    }
  613.    
  614.    return (ULONG)retval;
  615. }
  616.  
  617.  
  618. /* init chunkyiclass */
  619. Class *
  620. init_chunkyiclass (void)
  621. {
  622.    Class         *cl;
  623.    extern ULONG   HookEntry();
  624.    
  625.    
  626.    if (cl = MakeClass (NULL, "imageclass", NULL,
  627.                        sizeof (struct chunkyidata), 0))
  628.    {
  629.       cl->cl_Dispatcher.h_Entry = HookEntry;
  630.       cl->cl_Dispatcher.h_SubEntry = chunkyi_dispatcher;
  631.    }
  632.    
  633.    return cl;
  634. }
  635.  
  636.  
  637. /* free chunkyiclass */
  638. BOOL
  639. free_chunkyiclass (
  640.    Class  *cl)
  641. {
  642.    return FreeClass (cl);
  643. }
  644.